import numpy as np
from clothing_data_model import ClothingItem, Outfit, UserProfile, ContextInfo
from content_based_recommender import ContentBasedRecommender
from outfit_generator import OutfitGenerator
from reinforcement_learning_first import OutfitRLAgent
from database_connector import DatabaseConnector


class OutfitRecommendationSystemDB:
    def __init__(self, db_config):
        """
        初始化带数据库连接的服装搭配推荐系统

        参数:
            db_config: 数据库配置字典，包含 host, user, password, database
        """
        # 初始化数据库连接器
        self.db_connector = DatabaseConnector(
            host=db_config['host'],
            user=db_config['user'],
            password=db_config['password'],
            database=db_config['database']
        )

        # 从数据库加载服装项 - 初始化时不加载特定用户的衣物
        self.items_catalog = self.db_connector.load_clothing_items()

        # 初始化推荐组件
        self.content_recommender = ContentBasedRecommender(self.items_catalog)
        self.outfit_generator = OutfitGenerator(self.content_recommender, self.items_catalog)
        self.rl_agent = OutfitRLAgent(self.outfit_generator)

        # 用户缓存
        self.user_cache = {}

    def get_user_profile(self, user_id):
        """获取用户档案，优先从缓存中获取"""
        if user_id not in self.user_cache:
            # 从数据库加载用户档案
            self.user_cache[user_id] = self.db_connector.load_user_profile(user_id)

        return self.user_cache[user_id]

    def recommend_outfit(self, user_id, context=None, n_recommendations=1):
        """为用户推荐服装搭配"""
        user_profile = self.get_user_profile(user_id)
        error_info = None  # 初始化错误信息为None

        # 加载该用户的衣物
        user_items = self.db_connector.load_clothing_items(user_id)

        # 如果用户没有衣物，返回空列表和错误信息
        if not user_items:
            print(f"用户 {user_id} 没有衣物")
            return [], {"error_code": "NO_CLOTHES", "error_message": "您的衣橱中没有衣物，请先添加衣物"}

        # 为当前推荐创建临时的推荐组件，使用用户的衣物
        temp_content_recommender = ContentBasedRecommender(user_items)
        temp_outfit_generator = OutfitGenerator(temp_content_recommender, user_items)
        temp_rl_agent = OutfitRLAgent(temp_outfit_generator)

        # 生成候选搭配
        candidate_outfits = temp_outfit_generator.generate_outfits(
            user_profile, context, n_outfits=max(5, n_recommendations * 3))

        if not candidate_outfits:
            # 分析衣物不足的具体原因
            categories_count = {}
            for item in user_items:
                if item.category not in categories_count:
                    categories_count[item.category] = 0
                categories_count[item.category] += 1

            missing_categories = []
            for category in ["上衣", "裤子", "裙子", "鞋子"]:
                if category not in categories_count or categories_count[category] == 0:
                    missing_categories.append(category)
                elif category in categories_count and categories_count[category] < 2 and category == "上衣":
                    # 上衣可能需要多件来搭配
                    missing_categories.append(f"{category}(数量不足)")

            error_message = "无法生成有效搭配，"
            if missing_categories:
                error_message += f"缺少以下类别的衣物：{', '.join(missing_categories)}"
            else:
                error_message += "您的衣物可能不适合当前条件(温度、场景等)"

            return [], {"error_code": "INSUFFICIENT_ITEMS", "error_message": error_message}

        # 如果用户有足够的交互历史，使用RL代理选择搭配
        if len(user_profile.interaction_history) >= 5:
            selected_outfits = []

            for _ in range(min(n_recommendations, len(candidate_outfits))):
                # 从剩余候选中选择最佳搭配
                remaining_candidates = [o for o in candidate_outfits if o not in selected_outfits]
                if not remaining_candidates:
                    break

                selected_outfit = temp_rl_agent.select_outfit(user_profile, remaining_candidates, context)
                if selected_outfit:
                    selected_outfits.append(selected_outfit)

            return selected_outfits, None  # 返回推荐结果和None表示没有错误
        else:
            # 对于新用户，根据搭配评分选择
            outfit_scores = [(outfit, temp_outfit_generator.evaluate_outfit(outfit, context))
                             for outfit in candidate_outfits]
            outfit_scores.sort(key=lambda x: x[1], reverse=True)

            return [outfit for outfit, _ in outfit_scores[:n_recommendations]], None

    def provide_feedback(self, user_id, outfit, rating, style=None):
        """处理用户对搭配的反馈"""
        user_profile = self.get_user_profile(user_id)

        # 更新用户偏好
        user_profile.update_preferences(outfit, rating, style)

        # 更新RL代理的Q值
        self.rl_agent.update_q_values(user_profile, outfit, rating)

        # 保存反馈到数据库
        self.db_connector.save_user_feedback(user_id, outfit, rating, style)

        return user_profile

    def get_item_by_id(self, clothes_id):
        """根据ID获取服装项"""
        for item in self.items_catalog:
            if item.clothes_id == clothes_id:
                print(item)
                return item
        return None

    def create_outfit_from_ids(self, clothes_ids, user_id=None):
        """从衣服ID列表创建搭配"""
        items = []
        for clothes_id in clothes_ids:
            item = self.get_item_by_id(clothes_id)
            if item:
                items.append(item)

        if not items:
            return None

        outfit_id = hash(tuple(clothes_ids)) % 10000  # 使用哈希生成整数ID
        outfit = Outfit(outfit_id, items)

        # 设置user_id
        outfit.user_id = user_id

        # 保存搭配到数据库
        try:
            self.db_connector.save_outfit(outfit)
        except Exception as e:
            print(f"保存搭配失败: {e}")
            return None  # 如果保存失败，返回None

        return outfit

    def evaluate_custom_outfit(self, clothes_ids, context=None):
        """评估自定义搭配"""
        outfit = self.create_outfit_from_ids(clothes_ids)
        if not outfit:
            return 0.0

        return self.outfit_generator.evaluate_outfit(outfit, context)

    def get_similar_outfits(self, outfit, n=3):
        """查找与给定搭配相似的搭配"""
        similar_outfits = []

        # 获取搭配中每个衣服的相似衣服
        similar_items_by_category = {}
        for item in outfit.items:
            similar_items = self.content_recommender.find_similar_items(item, item.category, top_n=3)
            similar_items_by_category[item.category] = similar_items

        # 生成新的搭配组合
        for _ in range(n):
            new_outfit_items = []

            for category, items in similar_items_by_category.items():
                if items:
                    # 随机选择一个相似的衣服
                    selected_item = np.random.choice(items)
                    new_outfit_items.append(selected_item)

            if new_outfit_items:
                outfit_id = f"similar_outfit_{np.random.randint(10000)}"
                similar_outfit = Outfit(outfit_id, new_outfit_items)
                similar_outfits.append(similar_outfit)

        return similar_outfits

    def refresh_catalog(self):
        """刷新服装目录（从数据库重新加载）"""
        self.items_catalog = self.db_connector.load_clothing_items()
        self.content_recommender = ContentBasedRecommender(self.items_catalog)
        self.outfit_generator = OutfitGenerator(self.content_recommender, self.items_catalog)
